package com.ruoyi.web.controller.oauth2.client;

import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.controller.oauth2.common.CommonResult;
import com.ruoyi.web.controller.oauth2.config.OAuth2Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * OAuth 2.0 客户端
 *
 * 对应调用 OAuth2OpenController 接口
 */
@Component
public class OAuth2Client {

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private OAuth2Config oauth2Config;

    //    @Resource // 可优化，注册一个 RestTemplate Bean，然后注入
    private final RestTemplate restTemplate = new RestTemplate();

    /**
     * 使用 code 授权码，获得访问令牌
     *
     * @param code        授权码
     * @return 访问令牌
     */
    public CommonResult<Map<String, String>> postAccessToken(String code) {
        // 1.1 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        addClientHeader(headers, oauth2Config.getClientId(), oauth2Config.getClientSecret());
        // 1.2 构建请求参数
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("grant_type", "authorization_code");
        body.add("code", code);
        body.add("redirect_uri", oauth2Config.getRedirectUri());
        // body.add("state", ""); // 选填,填了会校验

        // 2. 执行请求
        ResponseEntity<CommonResult<Map<String, String>>> exchange = restTemplate.exchange(
                oauth2Config.getBaseUrl() + "/token",
                HttpMethod.POST,
                new HttpEntity<>(body, headers),
                new ParameterizedTypeReference<CommonResult<Map<String, String>>>() {
                }); // 解决CommonResult的泛型丢失
        Assert.isTrue(exchange.getStatusCode().is2xxSuccessful(), "响应必须是200成功");

        // 从统一门户获取token和userId
        CommonResult result = (CommonResult) exchange.getBody();

        if (result.getData() != null) {

            // 获取透传的userId
            String userId = ((Map<String, String>) result.getData()).get("userId");
            // 获取透传的userDoJsonString (只有第三方系统透传该信息，否则为空) 例如：{"nickname":"管理员","userId":"1","username":"admin"}
            String userDoJsonString = ((Map<String, String>) result.getData()).get("userDoJsonString");
            System.out.println("第三方系统透传userDo： " + userDoJsonString);

            // 根据userId生成子系统token
            SysUser user = userService.selectUserById(Long.parseLong(userId));
            String token = tokenService.createToken(
                    new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user))
            );

            Map<String, String> map = new HashMap<>();
            map.put("token", token);
            result.setData(map);
        }
        return result;
    }

    private static void addClientHeader(HttpHeaders headers, String clientId, String clientSecret) {
        // client 拼接，需要 BASE64 编码
        String client = clientId + ":" + clientSecret;
        client = Base64Utils.encodeToString(client.getBytes(StandardCharsets.UTF_8));
        headers.add("Authorization", "Basic " + client);
    }

}
